package com.chenjt.juc.four_lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 注释：
 *
 * @author chenjt
 * @date 2024/7/6 17:21
 */
public class ReEntryLockDemo {


    public synchronized void m1(){
        // 指的是可重复可递归调用的锁，在外层使用锁之后，在内层仍让可以使用，并且不发生死锁，这样是锁就叫做可重入锁
        System.out.println(Thread.currentThread().getName() + "\t ------come in");
        m2();
        System.out.println(Thread.currentThread().getName() + "\t ------end");
    }

    public synchronized void m2(){
        System.out.println(Thread.currentThread().getName() + "\t ------come in");
        m3();
    }

    public synchronized void m3(){
        System.out.println(Thread.currentThread().getName() + "\t ------come in");
    }


    static Lock lock = new ReentrantLock();

    public static void main(String[] args) {

        /**
         * synchronized可重入锁演示
         * 输出结果：
         * t1	 ----外层调用
         * t1	 ----中层调用
         * t1	 ----内层调用
         */
//        reEntryM1();

        /**
         * synchronized
         * 以下结果说明内层不管加了多少锁，只要最外面的锁拿到了，后面synchronized用的都是同一把锁
         * 输出结果：
         * t1	 ------come in
         * t1	 ------come in
         * t1	 ------come in
         * t1	 ------end
         */
//        reEntryM2();


        /**
         * 以下结果说明，ReentrantLock也是可重入锁
         * t1线程的输出结果：
         * t1	 ----come in外层调用
         * t1	 ----come in内层调用
         *
         * 当t1线程中有一个锁不释放，启动第二个线程时，第二个线程由于无法获得锁，导致第二个线程无法执行
         *
         */
        new Thread(()->{
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t ----come in外层调用");
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "\t ----come in内层调用");
                } finally {
                    // 由于加锁次数和解次数不一样，第二个线程始终无法获取到锁，导致一直在等待
//                    lock.unlock();
                }
            } finally {
                lock.unlock();
            }
        },"t1").start();

        new Thread(()->{
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "\t ----come in内层调用");
            } finally {
                lock.unlock();
            }
        },"t2").start();




    }


    private static void reEntryM1() {

        final Object object = new Object();

        new Thread(()->{
            synchronized (object){
                System.out.println(Thread.currentThread().getName() + "\t ----外层调用");
                synchronized (object){
                    System.out.println(Thread.currentThread().getName() + "\t ----中层调用");
                    synchronized (object){
                        System.out.println(Thread.currentThread().getName() + "\t ----内层调用");
                    }
                }
            }

        },"t1").start();

    }

    private static void reEntryM2() {
        ReEntryLockDemo reEntryLockDemo = new ReEntryLockDemo();
        new Thread(()->{
            reEntryLockDemo.m1();
        },"t1").start();
    }


}
